﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ExplorerPlus.DomainObjects;
using ExplorerPlus.PersistenceLayer.Xml;

namespace ExplorerPlus.PersistenceLayer
{
    internal class XmlPersistence : IPersistence
    {
        private int selectedCategory = -1;
        private DataStore ds;

        public List<FlyWeightItem> GetFlyWeightCategories()
        {
            List<FlyWeightItem> categories = new List<FlyWeightItem>();

            foreach (string name in Enum.GetNames(typeof(Categories)))
            {
                FlyWeightItem item = new FlyWeightItem();
                item.Id = (int)Enum.Parse(typeof(Categories), name, false);
                item.Name = name;
                categories.Add(item);
            }

            return categories;
        }

        public List<FlyWeightItem> GetFlyWeightCategoryFields(int categoryId)
        {
            List<FlyWeightItem> fields = new List<FlyWeightItem>();

            Repository xml = new Repository(Enum.GetName(typeof(Categories), categoryId));
            Metadata meta = xml.LoadMetadata();

            var query = from o in meta.Field
                        where o.IsSearchable == true
                        orderby o.FieldName
                        select new
                        {
                            o.FieldId,
                            o.FieldName
                        };

            foreach (var record in query)
            {
                FlyWeightItem item = new FlyWeightItem();
                item.Id = record.FieldId;
                item.Name = record.FieldName;
                fields.Add(item);
            }

            return fields;
        }

        public List<FlyWeightItem> GetFlyWeightCategoryFieldItems(int categoryId, int fieldId)
        {
            CacheDataStore(categoryId);

            List<FlyWeightItem> items = new List<FlyWeightItem>();

            var query = (from o in ds.ItemProperty
                         where o.FieldId == Convert.ToInt16(fieldId)
                         orderby o.ItemPropertyValue.ToLower()
                         select new
                         {
                             o.ItemPropertyValue,
                             o.FieldId
                         }).Distinct();

            foreach (var record in query)
            {
                FlyWeightItem item = new FlyWeightItem();
                item.Id = record.FieldId;
                item.Name = record.ItemPropertyValue;
                items.Add(item);
            }

            return items;
        }

        public List<FlyWeightItem> GetFlyWeightItems(int categoryId, int fieldId, string fieldValue)
        {
            CacheDataStore(categoryId);
            List<FlyWeightItem> items = new List<FlyWeightItem>();

            var query = (from item in ds.Item
                         join itemProp in ds.ItemProperty
                         on item.ItemId equals itemProp.ItemId
                         where itemProp.FieldId == Convert.ToInt16(fieldId)
                         && itemProp.ItemPropertyValue == fieldValue
                         orderby item.ItemName
                         select new
                         {
                             item.ItemId,
                             item.ItemName
                         }).Distinct();

            foreach (var record in query)
            {
                FlyWeightItem item = new FlyWeightItem();
                item.Id = record.ItemId;
                item.Name = record.ItemName;
                items.Add(item);
            }

            return items;
        }

        public Item GetItem(int categoryId, int itemId)
        {
            CacheDataStore(categoryId);

            Item item = new Item(categoryId);

            DataStore.ItemRow row = ds.Item.FindByItemId(itemId);

            if (row != null)
            {
                item = new Item(categoryId, row.ItemId);
                item.ItemName = row.ItemName;
                item.FilePath = row.FilePath;

                DataStore.ItemPropertyRow[] drArr = row.GetItemPropertyRows();

                foreach (DataStore.ItemPropertyRow dr in drArr)
                {
                    Item.ItemProperty itemProperty = new Item.ItemProperty();
                    itemProperty.FieldId = dr.FieldId; 
                    itemProperty.FieldName = "";// reader["FieldName"].ToString();
                    itemProperty.ItemPropertyId = dr.ItemPropertyId;
                    itemProperty.ItemPropertyValue = dr.ItemPropertyValue;
                    item.ItemProperties.Add(itemProperty);
                }
            }

            return item;
        }

        public Item GetItemByName(int categoryId, string itemName)
        {
            CacheDataStore(categoryId);

            System.Data.DataRow[] rows = ds.Item.Select("ItemName = '" + itemName.Replace("'", "''") + "'");
            if (rows != null && rows.Length > 0)
            {
                return GetItem(categoryId, 1);
            }

            return null;
        }

        private void CacheDataStore(int categoryId)
        {
            if (selectedCategory != categoryId || ds == null)
            {
                System.Diagnostics.Debug.WriteLine("data is cached.", "XmlPersistence");
                Repository xml = new Repository(Enum.GetName(typeof(Categories), categoryId));
                ds = xml.LoadDataStore();
                selectedCategory = categoryId;
            }
        }

        public Plugin GetCategoryPlugins(int categoryId)
        {
            Repository xml = new Repository(Enum.GetName(typeof(Categories), categoryId));
            Metadata meta = xml.LoadMetadata();

            Plugin plugin = new Plugin();

            if (meta.Plugin.Rows.Count > 0)
            {
                plugin.ImportPlugin = meta.Plugin[0].ImportPlugin;
                plugin.ItemDetailViewPlugin = meta.Plugin[0].ItemDetailViewPlugin;
                plugin.WebSearchPlugin = meta.Plugin[0].WebSearchPlugin;
                plugin.WebSearchViewPlugin = meta.Plugin[0].WebSearchViewPlugin;
            }

            return plugin;
        }

        #region IPersistence Members


        public bool SaveItem(Item item)
        {
            if (ds == null)
            {
                CacheDataStore(item.CategoryId);
            }
            if (ds != null)
            {
                DataStore.ItemRow dr = ds.Item.NewItemRow();
                
                if (item.ItemId > 0)
                {
                    dr = ds.Item.FindByItemId(item.ItemId);
                    DataStore.ItemPropertyRow[] drArr = dr.GetItemPropertyRows();
                    foreach (DataStore.ItemPropertyRow drItemProp in drArr)
                    {
                        drItemProp.Delete();
                    }
                }

                dr.ItemName = item.ItemName;
                dr.FilePath = item.FilePath;

                if (item.ItemId < 0)
                {
                    ds.Item.AddItemRow(dr);
                    item.ItemId = dr.ItemId;
                }

                for (int i = 0; i < item.ItemProperties.Count; i++)
                {
                    Item.ItemProperty itemProp = item.ItemProperties[i];
                    DataStore.ItemPropertyRow drItemProp = ds.ItemProperty.NewItemPropertyRow();
                    drItemProp.FieldId = Convert.ToInt16(itemProp.FieldId);
                    drItemProp.ItemId = item.ItemId;
                    drItemProp.ItemPropertyValue = itemProp.ItemPropertyValue;
                    ds.ItemProperty.AddItemPropertyRow(drItemProp);
                    itemProp.ItemPropertyId = drItemProp.ItemPropertyId;
                }

                Repository xml = new Repository(Enum.GetName(typeof(Categories), item.CategoryId));
                return xml.UpdateDataStore(ds);
            }
            return false;
        }

        public void DeleteItem(int categoryId, int itemId)
        {
            if (ds != null)
            {
                DataStore.ItemRow dr = ds.Item.FindByItemId(itemId);
                if (dr != null)
                {
                    dr.Delete();
                    Repository xml = new Repository(Enum.GetName(typeof(Categories), categoryId));
                    xml.UpdateDataStore(ds);
                }
            }
        }

        #endregion

        public void ClearCache()
        {
            ds = null;
        }
    }
}
